約 2,889,286 件
https://w.atwiki.jp/bannerlord/pages/92.html
基本事項用語 実装パターン レイヤー追加パターンの実装例Example UI Opponent Health Bar 基本事項 用語 Gauntlet UI Bannerlord のユーザーインターフェースに用いられているフレームワークです。 Model-View-ViewModel アーキテクチャー Gauntlet UI は Model-View-ViewModel (MVVM) と呼ばれるアーキテクチャーパターンを採用しています。要は、ゲームの領域、UI の領域、その2つを仲介する領域、の3層に分離させることで、情報を整理しやすく、また分業しやすくするという発想のようです。UI の MOD の場合、実装が必要なのはこの内の View と ViewModel になります。 この辺は、WPF や XAML を触ったことのある方ならお馴染みなのかもしれませんが、そうでない方も、あまり深く考えずに概念として何となく把握していれば大丈夫です。 ウィジェット GUI を構成する部品です。TaleWorlds.GauntletUI や TaleWorlds.MountAndBlade.GauntletUI.Widgets あたりに一通り揃っています。基本的にはこれらで事足りるので、自分でウィジェットを定義するということはあまり無いのではないかと思われます。 Prefab GUI のレイアウトを定義する XML ファイルです。プレハブ建築のプレハブと同じで、出来合いの部品 (ウィジェットや他の Prefab) をどういう風に組み合わせて配置するかを指定し、なにがしかの UI 機能を提供する大きめの部品として独立させたものです。 Prefab は TaleWorlds.Engine.GauntletUI.GauntletLayer.LoadMovie() するたびに読み込まれるので、ゲーム起動中にレイアウトを確認しながら編集していくなんてこともできます。(もちろん、構文エラー等があればその時点でクラッシュしますが) Brush GUI のスタイルを定義する XML ファイルです。Prefab と Brush の関係は、HTML と CSS の関係と似たようなものだそうです。 Widget に複数の状態が定義されていれば、それぞれの状態に応じたスプライト画像やフォント等を Brush に持たせることで、Widget に視覚的変化を与えることができます。例えば、Wiget がデフォルト状態にある時のスプライト、マウスオーバー時のスプライト、クリックした時のスプライト、Disable 時のスプライトなどをまとめられる、と言えばわかりやすいでしょうか。 ブラシは、Native 等の公式モジュールの GUI\Brushes に多数定義されています。 実装パターン 一部のパターンでしか実験していません。「たぶんこういうことだろう」レベルの推測が混じっています。 追加 既存の UI スクリーンにレイヤーを追加し、そこに自前の GUI を描画する (AddLayer)。 標準的な方法です。自分で View も ViewModel も用意するので好きなようにデザインできますが、既存の GUI そのものを書き換えることはできません。 モジュールとしての競合は起こりませんが、意図せず他の MOD の GUI と表示位置がかぶってしまうことはあり得ます。 改変 (未検証) 既存の UI スクリーンのレイアウトだけを変更する (XML 改変)。 使用するデータソース (ViewModel) はそのままで、XML の書き換えによって GUI の配置なんかを変える方法です。簡単だと思いますが、おそらくやれることは限定的です。また、MOD の競合が発生しうる方法だと思われます。 上書き (未検証) 既存の UI スクリーン全体をオーバーライドする (OverrideView)。 上書きする UI スクリーンが提供していた機能を自分で実装することになるため難易度は高いでしょう。また、MOD の競合が発生しうる方法だと思われます。 新規作成 自前の UI スクリーンを作成し、何かのイベントに伴ってそのスクリーンを呼び出す (PushScreen)。 Push/Pop のスタック形式なのでモーダルなポップアップとかに向いていると思います。 一部改変 たとえばオプション項目の追加などがこれに当たりますが、現状ではできないようです。 ただ、可能にする方法は検討されているとのこと。 Beyond that, we continue to work on Adding support for adding options to the options screen レイヤー追加パターンの実装例 Example UI ExampleUI プロジェクトSubModule.cs ViewsSampleMapView.cs SampleMissionView.cs ViewModelsTestWindowVM.cs ExampleUI.Window.xml View と ViewModel の関係がはっきりするように階層 (名前空間) を分けています。 ExampleUI.Window.xml は、 [Bannerlord インストールフォルダー]\Modules\ExampleUI\GUI\Prefabs フォルダーを作成し、その中に保存します。 MVVM では疎結合 (各層の結びつきが緩やか) なのが望ましいとされているそうなので、参照はできるだけ一方向になるようにしましょう。 すなわち、 View が ViewModel のインスタンスを持ち、その逆方向のアクセスはしない Model (ゲーム内の要素) に属するデータの加工は View の中では行わず、ViewModel で行う という感じです。 コード +SubModule.cs モジュールのエントリーポイントです。 using ExampleUI.Views;using SandBox.View.Map;using System;using TaleWorlds.Core;using TaleWorlds.Engine.Screens;using TaleWorlds.MountAndBlade;using TaleWorlds.MountAndBlade.View.Missions;using TaleWorlds.MountAndBlade.View.Screen; namespace ExampleUI{ public class SubModule MBSubModuleBase { private MissionView _missionView; private MapView _mapView; // Mission (平たく言えば、キャラクターが動き回ったり攻撃したりできる状況) に対する // MOD の処理 (ビヘイビアー) の登録はこのメソッドで行います。 // OnBeforeMissionBehaviourInitialize() と OnMissionBehaviourInitialize() の違いは // MissionBehaviour.OnBehaviourInitialize() の前に呼ばれるか後によばれるかです。 public override void OnBeforeMissionBehaviourInitialize(Mission mission) { base.OnBeforeMissionBehaviourInitialize(mission); // ViewCreatorManager.CreateMissionView() は一応ファクトリーメソッドっぽいのですが、 // 公式のコードには、これを介さず単に new MissionView() しているものもあったりして // よく分かりません。どっちにしろ動くのは動きます。 _missionView = ViewCreatorManager.CreateMissionView SampleMissionView (false, mission, Array.Empty object ()); mission.AddMissionBehaviour(_missionView); /* mission.AddMissionBehaviour(_missionView = new SampleMissionView()); */ // このサンプルでは、全ての Mission でテスト GUI が表示されてしまいますが、 // 戦闘シーンだけに表示したいなどといった場合、何らかの工夫が必要になるでしょう。 // // ちなみに、OnBeforeMissionBehaviourInitialize() 時点で mission.Mode は MissionMode.StartUp 固定なので、 // 以下の方法は使えませんでした。 /* if (mission.Mode == MissionMode.Battle) { _missionView = ViewCreatorManager.CreateMissionView SampleMissionView (false, mission, Array.Empty object ()); mission.AddMissionBehaviour(_missionView); } */ } // MapScreen (ワールドマップの描画スクリーン) には OnBeforeMissionBehaviourInitialize() に相当する // メソッドが用意されていないので、スクリーンの Push/Pop イベントを利用してレイヤーを挿入しています。 public override void OnGameInitializationFinished(Game game) { base.OnGameInitializationFinished(game); ScreenManager.OnPushScreen += OnScreenManagerPushScreen; // Obsolete /* ScreenManager.OnPopScreen += OnScreenManagerPopScreen; */ } public override void OnGameEnd(Game game) { ScreenManager.OnPushScreen -= OnScreenManagerPushScreen; // Obsolete /* ScreenManager.OnPopScreen -= OnScreenManagerPopScreen; */ base.OnGameEnd(game); } private void OnScreenManagerPushScreen(ScreenBase pushedScreen) { if (pushedScreen is MapScreen mapScreen) { _mapView = mapScreen.AddMapView SampleMapView (Array.Empty object ()); } /* else if (pushedScreen is MissionScreen missionScreen missionScreen.Mission != null) { // MissionScreen は、まず空の MissionScreen を Push してから、ローディング画面を // 表示しつつスクリーンを初期化していく感じなので、MapScreen と同じ手法は使えません。 // // この時点で missionScreen.Mission には中身がないので、CreateMissionView() は失敗します。 _missionView = ViewCreatorManager.CreateMissionView SampleMissionView (false, missionScreen.Mission, Array.Empty object ()); missionScreen.AddMissionView(_missionView); } */ } [Obsolete("1.6.0より前の手法")] private void OnScreenManagerPopScreen(ScreenBase poppedScreen) { if (_mapView != null poppedScreen is MapScreen mapScreen) { // 1.6.0 からは MapScreen が破棄される際に勝手に MapView.OnFinalize() を呼んでくれるようになったので // MapView と MapScreen の寿命を同じにする限りでは、MapScreen.RemoveMapView() をする必要がなくなりました。 mapScreen.RemoveMapView(_mapView); _mapView = null; } else if (_missionView != null poppedScreen is MissionScreen) { // MissionView については、MissionScreen.OnEndMission() が OnMissionScreenFinalize() の呼び出しから // RemoveMissionBehaviour() まで勝手にやってくれます。 _missionView = null; } // したがって、_mapView と _missionView はもはや必要のないフィールドなのですが、説明用に残してあります。 } }} +SampleMapView.cs using ExampleUI.ViewModels;using SandBox.View.Map;using TaleWorlds.Engine.GauntletUI;using TaleWorlds.GauntletUI.Data;using TaleWorlds.InputSystem;using TaleWorlds.Library; namespace ExampleUI.Views{ public class SampleMapView MapView { private TestWindowVM _dataSource; private GauntletLayer _gauntletLayer; private IGauntletMovie _gauntletMovie; protected override void CreateLayout() { base.CreateLayout(); _dataSource = new TestWindowVM(); // localOrder (レイヤーの優先度) が小さいほど、他のレイヤーより下 (画面奥) に描画されます。 // // 例えば、部隊が町などに入った際に左に表示されるメニュー (GauntletMenuBase) のレイヤー優先度は 100 なので、 // それより小さい値に設定すればテストウィンドウがメニューの下に表示されるようになります。 // ESC メニュー (GauntletMapEscapeMenu) のレイヤー優先度が 4400 なので、これよりは小さい値に // した方がよさそうです。あるいは、ESC メニュー表示中は GUI を非表示にする処理を追加しましょう。 _gauntletLayer = new GauntletLayer(4000); Layer = _gauntletLayer; // Movie (= Screen に投影するもの) とは、XML から取得した UI の構造と、ViewModel (表示するデータ) を合わせた概念です。 _gauntletMovie = _gauntletLayer.LoadMovie("ExampleUI.Window", _dataSource); // このレイヤーの描画領域に対して行われた入力のうち、受け取るものをビットフラグによって管理しています。 _gauntletLayer.InputRestrictions.SetInputRestrictions(true, InputUsageMask.MouseButtons); MapScreen.AddLayer(_gauntletLayer); } // MapScreen.OnFinalize() によって呼び出されます。 protected override void OnFinalize() { MapScreen.RemoveLayer(_gauntletLayer); _gauntletLayer.InputRestrictions.ResetInputRestrictions(); _gauntletLayer.ReleaseMovie(_gauntletMovie); _gauntletLayer = null; Layer = null; _dataSource.OnFinalize(); base.OnFinalize(); } // 毎ティック行う処理を記述します。 // // dt デルタタイム。前回のティックからの経過時間です。 protected override void OnFrameTick(float dt) { base.OnFrameTick(dt); if (MapScreen.Input.IsKeyPressed(InputKey.Home)) { _dataSource.IsVisible ^= true; // bool 反転 } } }} +SampleMissionView.cs SampleMapView とは使用するメソッドが違うだけで、やっていることは全く同じです。 using ExampleUI.ViewModels;using TaleWorlds.Engine.GauntletUI;using TaleWorlds.GauntletUI.Data;using TaleWorlds.InputSystem;using TaleWorlds.MountAndBlade.View.Missions; namespace ExampleUI.Views{ public class SampleMissionView MissionView { private TestWindowVM _dataSource; private GauntletLayer _gauntletLayer; private IGauntletMovie _gauntletMovie; public override void OnMissionScreenInitialize() { base.OnMissionScreenInitialize(); _dataSource = new TestWindowVM(); // localOrder (レイヤーの優先度) が小さいほど、他のレイヤーより下 (画面奥) に描画されます。 // // ESC メニュー (GauntletMissionEscapeMenu) のレイヤー優先度が 50 なので、 これよりは小さい // した方がよさそうです。あるいは、ESC メニュー表示中は GUI を非表示にする処理を追加しましょう。 _gauntletLayer = new GauntletLayer(40); // Movie (= Screen に投影するもの) とは、XML から取得した UI の構造と、ViewModel (表示するデータ) を合わせた概念です。 _gauntletMovie = _gauntletLayer.LoadMovie("ExampleUI.Window", _dataSource); // このレイヤーの描画領域に対して行われた入力のうち、受け取るものをビットフラグによって管理しています。 /* _gauntletLayer.InputRestrictions.SetInputRestrictions(true, InputUsageMask.MouseButtons); */ // Mission 中はマウスを視点移動や攻撃に使うため、ポインティングデバイスとして使うには、 // 戦闘結果画面において、Tab を押す - リザルトとマウスカーソル表示 - ボタンが押せるようになる // とやっているような感じで、キーボード操作を挟んで切り替える必要があります。 // 今回はそこまで実装していないため、Mission 中は閉じるボタンをクリックできません。 MissionScreen.AddLayer(_gauntletLayer); } // MissionScreen.OnEndMission() によって呼び出されます。 public override void OnMissionScreenFinalize() { MissionScreen.RemoveLayer(_gauntletLayer); _gauntletLayer.ReleaseMovie(_gauntletMovie); _gauntletLayer = null; _dataSource.OnFinalize(); base.OnMissionScreenFinalize(); } // 毎ティック行う処理を記述します。 // // dt デルタタイム。前回のティックからの経過時間です。 public override void OnMissionScreenTick(float dt) { base.OnMissionScreenTick(dt); if (Input.IsKeyPressed(InputKey.Home)) { _dataSource.IsVisible ^= true; // bool 反転 } } }} +TestWindowVM.cs ViewModel とは View を抽象化したものです。今回の例では、 画面左上にウィンドウを表示 ウィンドウの中には閉じるボタン1つだけ 閉じるボタンを押すとウィンドウが閉じる Home キーでも開いたり閉じたりできる というモデルで行きます。 TestWindowVM は View から完全に分離されているので、今回使う2つの View どちらにもそのまま使用できます。 using TaleWorlds.Core;using TaleWorlds.Library;// View-ViewModel の参照を一方向にするため using ExampleUI.Views をやっていません。 namespace ExampleUI.ViewModels{ // ViewModel は全て TaleWorlds.Library.ViewModel を継承して作ります。 // クラス名に VM を付けなければならないという決まりがあるわけではないのですが、 // 公式の ViewModel は全て VM を付けているようなので踏襲しています。 public class TestWindowVM ViewModel { private bool _isVisible; public TestWindowVM() { IsVisible = true; } // ViewModel のプロパティやメソッドは、View の LoadMovie で関連付けられた XML Prefab から参照できます。 // XML の方を見てもらえば、それらがどのように使われているか分かるかと思います。 [DataSourceProperty] public bool IsVisible { get = _isVisible; set { if (_isVisible != value) { _isVisible = value; // このメソッドを呼ぶことで、TestWindowVM にバインディングされた View に対して // TestWindowVM.IsVisible プロパティの変更通知が行き、プロパティを参照している // ウィジェットの方も状態が変化するという仕組みです。 OnPropertyChangedWithValue(value, "IsVisible"); } } } // こちらは値の変更がない固定ラベルなので、set アクセサーや OnPropertyChangedWithValue() は使っていません。 [DataSourceProperty] public string WindowTitle = "Test Window"; // 以前はラベルにも日本語が使えたのですが、1.6.0 から文字化けするようになってしまいました。 [DataSourceProperty] public string CloseButtonLabel = "Close"; // ButtonWidget のクリックイベントに応じて呼ばれるよう、ExampleUI.Window.xml に記述してあります。 public void OnCloseButtonClick() { IsVisible = false; InformationManager.DisplayMessage(new InformationMessage("ウィンドウを閉じました。\n再度開くには Home キーを押してください。")); } }} DataSourceProperty 属性 公式の ViewModel 派生クラスのプロパティにはこの属性を与えられたものが多く見受けられますが、ソースコードを見ても特に何か定義されているわけでもなく、実際、属性を付けても付けなくても動作は変わらないように見えます。唯一、ViewModel.Properties プロパティで DataSourceProperty のリストを作るのに使われているようですが、このプロパティは他からは特に参照されていないようです。一応、XML から参照されるプロパティには全てこの属性を付けてあります。 +ExampleUI.Window.xml ExampleUI で使うウィンドウの Prefab です。 Prefab Window Widget WidthSizePolicy="Fixed" HeightSizePolicy="Fixed" SuggestedWidth="400" SuggestedHeight="300" IsVisible="@IsVisible" Children Standard.Window Parameter.Title="@WindowTitle" Children Standard.PopupCloseButton Parameter.ButtonText="@CloseButtonLabel" Parameter.ButtonAction="OnCloseButtonClick" / /Children /Standard.Window /Children /Widget /Window /Prefab Widget TaleWorlds.GauntletUI.Widget クラスです。Widget クラスは基底クラスとしてデータを保持しているだけで、UI としての機能はありません。ここでは、他の UI をまとめるコンテナとして使っています。 SizePolicy Fixed 指定の幅にしますStretchToParent 親要素の幅に合わせますCoverChildren 子要素を全て表示できる幅にします IsVisible="@IsVisible" 名前が同じで分かりにくいですが、最初の方が Widget クラスのプロパティ、@付きの方がデータソースとなる ViewModel 派生クラス (今回の例で言えば TestWindowVM) のプロパティとなります。このように指定することで、TestWindowVM.IsVisible の中で呼んである ViewModel.OnPropertyChangedWithValue() によって発せられたイベントが Widget に届くようになり、TestWindowVM.IsVisible と Widget.IsVisible が連動するわけです。 Standard.Window と Standard.PopupCloseButton 公式の Prefab を使っています。公式の Prefab も大半は各シチュエーションに特化した大型のものばかりで、そのままでの再利用はしにくいですが、Native\GUI\Prefabs\Standard にあるものは比較的小型で汎用性が高くなっています。 Parameter Standard.Window 等の Prefab では Parameter が宣言されているものがあり、Widget のプロパティに値を渡すのと同じ感覚で、Prefab 自体に値を渡すことができます。Prefab 側では、自分の中の Widget に受け取った値を渡すよう記述されています。 結果 MapScreen MissionScreen 左上にウィンドウっぽいものが表示されています。Prefab を適当に選んだのでデザインがめちゃくちゃですが、画面上にとりあえず何かを表示する例ということで大目に見てください。 手順をおおまかにまとめると、 作りたい UI を考える その構想に沿った GUI の構造 (Prefab) と表示するデータ (ViewModel) を用意する 用意したものを、表示先がワールドマップなら MapView、戦闘などの Mission なら MissionView で LoadMovie() する View をスクリーンに追加する となります。 Opponent Health Bar 今度はもう少し実践的な MOD を作っていきます。見出しが示す通り、戦っている相手の HP バーを表示する MOD です。 イメージとしてはこんな感じ。 OpponentHealthBar プロジェクトSubModule.cs MissionOpponentHealthBar.cs OpponentHealthVM.cs OpponentHealthBar.xml OpponentHealthBar.xml は、 [Bannerlord インストールフォルダー]\Modules\OpponentHealthBar\GUI\Prefabs の中に保存します。 バージョン1 それでは、とりあえず簡単に文字で表示するところから始めてみます。 +SubModule.cs using System;using TaleWorlds.MountAndBlade;using TaleWorlds.MountAndBlade.View.Missions; namespace OpponentHealthBar{ public class SubModule MBSubModuleBase { public override void OnBeforeMissionBehaviourInitialize(Mission mission) { base.OnBeforeMissionBehaviourInitialize(mission); mission.AddMissionBehaviour( ViewCreatorManager.CreateMissionView MissionOpponentHealthBar (false, mission, Array.Empty object ())); } }} +MissionOpponentHealthBar.cs using TaleWorlds.Core;using TaleWorlds.Engine.GauntletUI;using TaleWorlds.GauntletUI.Data;using TaleWorlds.MountAndBlade;using TaleWorlds.MountAndBlade.View.Missions; namespace OpponentHealthBar{ public class MissionOpponentHealthBar MissionView { private OpponentHealthVM _dataSource; private GauntletLayer _gauntletLayer; private IGauntletMovie _gauntletMovie; public MissionOpponentHealthBar() { ViewOrderPriorty = 20; } public override void OnMissionScreenInitialize() { base.OnMissionScreenInitialize(); _dataSource = new OpponentHealthVM(); _gauntletLayer = new GauntletLayer(ViewOrderPriorty); _gauntletMovie = _gauntletLayer.LoadMovie("OpponentHealthBar", _dataSource); MissionScreen.AddLayer(_gauntletLayer); } public override void OnMissionScreenFinalize() { MissionScreen.RemoveLayer(_gauntletLayer); _gauntletLayer.ReleaseMovie(_gauntletMovie); _gauntletLayer = null; _dataSource.OnFinalize(); base.OnMissionScreenFinalize(); } // 画面中央 (マウスカーソルの位置) と、一番手前にある IFocusable なオブジェクトとが交差した瞬間に呼ばれます。 // // agent フォーカスした Agent。シングルプレイだと、おそらく常に Agent.Main (プレイヤーキャラクター) です。 // focusableObject フォーカスされたもの // isInteractable Talk や Use などのインタラクトが可能か // // フォーカスが 10m までしか利かないのは MissionMainAgentInteractionComponent.FocusTick() で // 決められた仕様なのでどうしようもありません。 public override void OnFocusGained(Agent agent, IFocusable focusableObject, bool isInteractable) { base.OnFocusGained(agent, focusableObject, isInteractable); _dataSource.OnFocusChanged(focusableObject); } // 今までフォーカスされていた IFocusable なオブジェクトから、フォーカスが外れた瞬間に呼ばれます。 // // agent フォーカスしていた Agent。シングルプレイだと、おそらく常に Agent.Main (プレイヤーキャラクター) です。 // focusableObject フォーカスされていたもの public override void OnFocusLost(Agent agent, IFocusable focusableObject) { base.OnFocusLost(agent, focusableObject); _dataSource.OnFocusChanged(focusableObject); } // Agent が何らかの攻撃を受けた際に呼ばれます。 // // affectedAgent 攻撃を受けた Agent // affectorAgent 攻撃を行った Agent // damage ダメージ量 // affectorWeapon 使用された武器 public override void OnAgentHit(Agent affectedAgent, Agent affectorAgent, int damage, in MissionWeapon affectorWeapon) { base.OnAgentHit(affectedAgent, affectorAgent, damage, affectorWeapon); _dataSource.OnAgentHit(affectedAgent); } // Agent が戦闘不能になった際に呼ばれます。 // // affectedAgent 攻撃を受けた Agent // affectorAgent 攻撃を行った Agent // agentState Agent の状態 // blow とどめの一撃の内容 // // 似たようなメソッドに OnAgentDeleted がありますが、そちらは // 戦闘不能になって倒れている Agent が時間経過や表示限界により消滅する際に呼ばれるようです。 public override void OnAgentRemoved(Agent affectedAgent, Agent affectorAgent, AgentState agentState, KillingBlow blow) { base.OnAgentRemoved(affectedAgent, affectorAgent, agentState, blow); _dataSource.OnAgentRemoved(affectedAgent); } }} +OpponentHealthVM.cs 今度のモデルは、 Agent (Mission 中に動きうるもの) の HP 現在値/最大値 を文字で表示する Agent にフォーカスが合うと表示、フォーカスが外れると非表示 とします。 using System;using TaleWorlds.Library;using TaleWorlds.MountAndBlade; namespace OpponentHealthBar{ public class OpponentHealthVM ViewModel { private Agent _opponent; private string _strValues; private bool _isVisible; private const string ValueFormat = "{0} / {1}"; public OpponentHealthVM() { _opponent = null; _strValues = string.Empty; _isVisible = false; } [DataSourceProperty] public string StrValues { get = _strValues; private set { if (_strValues != value) { _strValues = value; OnPropertyChangedWithValue(value, "StrValues"); } } } [DataSourceProperty] public bool IsVisible { get = _isVisible; set { if (_isVisible != value) { _isVisible = value; OnPropertyChangedWithValue(value, "IsVisible"); } } } // GUI に表示するデータの更新はこのメソッドで行います。 // ただし、ここに記述すればあとは勝手に更新されていくというものではないので、 // 自分が必要な場所では自分で呼び出さなければなりません。 public override void RefreshValues() { base.RefreshValues(); int currentValue = (int)Math.Ceiling(_opponent?.Health ?? 0f); int maxValue = (int)Math.Ceiling(_opponent?.HealthLimit ?? 0f); StrValues = string.Format(ValueFormat, currentValue, maxValue); IsVisible = _opponent != null; } public void OnFocusChanged(IFocusable focusableObject) { if (focusableObject is Agent possibleOpponent) { _opponent = (_opponent == null || _opponent != possibleOpponent) ? possibleOpponent null; RefreshValues(); } } public void OnAgentHit(Agent affectedAgent) { if (_opponent == affectedAgent) { RefreshValues(); } } public void OnAgentRemoved(Agent removedAgent) { if (_opponent == removedAgent) { // 先にフォーカスロストが発生してここには入らないかも。 OnFocusChanged(removedAgent); } } }} +OpponentHealthBar.xml Prefab Window Widget WidthSizePolicy="Fixed" HeightSizePolicy="Fixed" SuggestedWidth="430" SuggestedHeight="50" HorizontalAlignment="Center" VerticalAlignment="Top" MarginTop="250" IsVisible="@IsVisible" Children TextWidget Text="@StrValues" WidthSizePolicy="CoverChildren" HeightSizePolicy="CoverChildren" HorizontalAlignment="Center" VerticalAlignment="Center" Brush="Tooltip.Text" Brush.FontSize="24" / /Children /Widget /Window /Prefab Alignment 親要素の領域内のどちら側に寄せるかです。親要素より幅が小さい場合にしか効果がありません。この例の TextWidget で言うと、親要素は幅 430、自身は CoverChildren、つまり StrValues が入りきるだけの幅なので機能していますが、これを StretchToParent とかにすると、左寄せや右寄せが機能しなくなります。 Margin Left, Top, Right, Bottom のマージンです。幅+マージンが要素の実際の幅になります。 以上を実行した状態が下の画像です。 ちょっと見にくいですが、画面上部中央に相手の HP 100/100 が表示されていますね。フォーカスを外せば数字は消えます。しかし、今のところ町人だろうが馬だろうが Agent なら何にでも表示されてしまいますので、そこは改良が必要です。 バージョン2 次はバーの導入とその他の改良を行っていきたいと思います。 バー表示に使うのは FillBarWidget です。ソースコードや、FillBarWidget を使用している公式の Prefab を見てみると、FillBarWidget.MaxAmount プロパティと FillBarWidget.InitialAmmount プロパティに値を渡せばとりあえず動きそうです。よって、ViewModel 側でその値を用意してやる必要があります。 +OpponentHealthVM.cs [DataSourceProperty] public int CurrentValue { get = _currentValue; private set { if (_currentValue != value) { _currentValue = value; OnPropertyChangedWithValue(value, "CurrentValue"); } } } [DataSourceProperty] public int MaxValue { get = _maxValue; private set { if (_maxValue != value) { _maxValue = value; OnPropertyChangedWithValue(value, "MaxValue"); } } } // GUI に表示するデータの更新はこのメソッドで行います。 // ただし、ここに記述すればあとは勝手に更新されていくというものではないので、 // 自分が必要な場所では自分で呼び出さなければなりません。 public override void RefreshValues() { base.RefreshValues(); // 元々ローカル変数だったものを、View から参照できるようにプロパティに昇格しました。 CurrentValue = (int)Math.Ceiling(_opponent?.Health ?? 0f); MaxValue = (int)Math.Ceiling(_opponent?.HealthLimit ?? 0f); StrValues = string.Format(ValueFormat, CurrentValue, MaxValue); IsVisible = _opponent != null; } public void OnFocusChanged(IFocusable focusableObject) { // 適切な相手に表示されるよう条件を追加しました。 if (focusableObject is Agent possibleOpponent possibleOpponent.IsHuman possibleOpponent.IsEnemyOf(Agent.Main)) { _opponent = (_opponent == null || _opponent != possibleOpponent) ? possibleOpponent null; RefreshValues(); } } ViewModel にプロパティを追加したので、今度は Prefab を通じてそれらを FillBarWidget に渡します。 +OpponentHealthBar.xml Prefab Window FillBarWidget WidthSizePolicy="Fixed" HeightSizePolicy="Fixed" SuggestedWidth="430" SuggestedHeight="50" HorizontalAlignment="Center" VerticalAlignment="Top" MarginTop="250" ContainerWidget="FillBarContainer" FillWidget="FillVisualParent\FillVisual" MaxAmount="@MaxValue" InitialAmount="@CurrentValue" IsVisible="@IsVisible" Children Widget Id="FillVisualParent" WidthSizePolicy="Fixed" HeightSizePolicy="StretchToParent" SuggestedWidth="400" HorizontalAlignment="Center" VerticalAlignment="Center" MarginTop="10" MarginBottom="10" Sprite="BlankWhiteSquare" Color="#202020A0" Children BrushWidget Id="FillVisual" WidthSizePolicy="Fixed" HeightSizePolicy="StretchToParent" SuggestedWidth="400" HorizontalAlignment="Left" Brush="Mission.MainAgentHUD.HeroHealthBar.Fill" / /Children /Widget Widget Id="FillBarContainer" WidthSizePolicy="StretchToParent" HeightSizePolicy="StretchToParent" Sprite="options_memory_progress_frame" / TextWidget Text="@StrValues" WidthSizePolicy="CoverChildren" HeightSizePolicy="CoverChildren" HorizontalAlignment="Center" VerticalAlignment="Center" PositionYOffset="3" Brush="Tooltip.Text" Brush.FontSize="24" / /Children /FillBarWidget /Window /Prefab FillBarWidget バージョン1ではただの Widget だったトップレベルのウィジェットを FillBarWidget に変更してあります (3行目)。 FillVisual 赤ゲージの Brush を保持した BrushWidget の ID です (9行目)。このように、Widget には任意の ID がつけられます。それによって、他のウィジェットを操作するタイプのウィジェットに対し、操作対象がどれなのか伝えることができます。 ここでは、FillBarWidget.FillWidget プロパティに渡して、FillBarWidget が "FillVisual" の幅を操作できるようにしています。 親要素の "FillVisualParent" はゲージが減った部分を埋める背景画像です。"BlankWhiteSquare" という無地画像を、暗い半透明に着色・透過させて使っています。 FillBarContainer 14行目にある、スプライト画像を保持した Widget の ID です。これを FillBarWidget.ContainerWidget プロパティに渡してバーの枠としています。 ところで、Mission 用の GUI はそのままだとフォトモード中でも表示されてしまいます。構図を決めている間に GUI が表示されてしまうのは邪魔ですから、MissionView を使うときは、フォトモード中 GUI を非表示にする処理を追加しておきましょう。 +MissionOpponentHealthBar.cs // フォトモードで構図を決めている最中に GUI が表示されないようにするための処理です。 // この処理を入れても入れなくても、どちらにしろ出力される画像ファイルに GUI は写りません。 public override void OnPhotoModeActivated() { base.OnPhotoModeActivated(); _gauntletLayer._gauntletUIContext.ContextAlpha = 0f; } public override void OnPhotoModeDeactivated() { base.OnPhotoModeDeactivated(); _gauntletLayer._gauntletUIContext.ContextAlpha = 1f; } 結果 攻撃前 攻撃後 どうでしょう、一応 HP バーらしくなったのではないでしょうか。 他にも、与えたダメージ分のバーをスライドさせる視覚効果とか、フォーカスが外れてからバーが消えるまでに時間差を設けるとか、改良はいろいろ考えられますが、サンプルではここまでです。興味があったら自分の MOD として実装してみてください。 +コード最終形 SubModule.cs using System;using TaleWorlds.MountAndBlade;using TaleWorlds.MountAndBlade.View.Missions; namespace OpponentHealthBar{ public class SubModule MBSubModuleBase { public override void OnBeforeMissionBehaviourInitialize(Mission mission) { base.OnBeforeMissionBehaviourInitialize(mission); mission.AddMissionBehaviour( ViewCreatorManager.CreateMissionView MissionOpponentHealthBar (false, mission, Array.Empty object ())); } }} MissionOpponentHealthBar.cs using TaleWorlds.Core;using TaleWorlds.Engine.GauntletUI;using TaleWorlds.GauntletUI.Data;using TaleWorlds.MountAndBlade;using TaleWorlds.MountAndBlade.View.Missions; namespace OpponentHealthBar{ public class MissionOpponentHealthBar MissionView { private OpponentHealthVM _dataSource; private GauntletLayer _gauntletLayer; private IGauntletMovie _gauntletMovie; public MissionOpponentHealthBar() { ViewOrderPriorty = 20; } public override void OnMissionScreenInitialize() { base.OnMissionScreenInitialize(); _dataSource = new OpponentHealthVM(); _gauntletLayer = new GauntletLayer(ViewOrderPriorty); _gauntletMovie = _gauntletLayer.LoadMovie("OpponentHealthBar", _dataSource); MissionScreen.AddLayer(_gauntletLayer); } public override void OnMissionScreenFinalize() { MissionScreen.RemoveLayer(_gauntletLayer); _gauntletLayer.ReleaseMovie(_gauntletMovie); _gauntletLayer = null; _dataSource.OnFinalize(); base.OnMissionScreenFinalize(); } // 画面中央 (マウスカーソルの位置) と、一番手前にある IFocusable なオブジェクトとが交差した瞬間に呼ばれます。 // // agent フォーカスした Agent。シングルプレイだと、おそらく常に Agent.Main (プレイヤーキャラクター) です。 // focusableObject フォーカスされたもの // isInteractable Talk や Use などのインタラクトが可能か // // フォーカスが 10m までしか利かないのは MissionMainAgentInteractionComponent.FocusTick() で // 決められた仕様なのでどうしようもありません。 public override void OnFocusGained(Agent agent, IFocusable focusableObject, bool isInteractable) { base.OnFocusGained(agent, focusableObject, isInteractable); _dataSource.OnFocusChanged(focusableObject); } // 今までフォーカスされていた IFocusable なオブジェクトから、フォーカスが外れた瞬間に呼ばれます。 // // agent フォーカスしていた Agent。シングルプレイだと、おそらく常に Agent.Main (プレイヤーキャラクター) です。 // focusableObject フォーカスされていたもの public override void OnFocusLost(Agent agent, IFocusable focusableObject) { base.OnFocusLost(agent, focusableObject); _dataSource.OnFocusChanged(focusableObject); } // Agent が何らかの攻撃を受けた際に呼ばれます。 // // affectedAgent 攻撃を受けた Agent // affectorAgent 攻撃を行った Agent // damage ダメージ量 // affectorWeapon 使用された武器 public override void OnAgentHit(Agent affectedAgent, Agent affectorAgent, int damage, in MissionWeapon affectorWeapon) { base.OnAgentHit(affectedAgent, affectorAgent, damage, affectorWeapon); _dataSource.OnAgentHit(affectedAgent); } // Agent が戦闘不能になった際に呼ばれます。 // // affectedAgent 攻撃を受けた Agent // affectorAgent 攻撃を行った Agent // agentState Agent の状態 // blow とどめの一撃の内容 // // 似たようなメソッドに OnAgentDeleted がありますが、そちらは // 戦闘不能になって倒れている Agent が時間経過や表示限界により消滅する際に呼ばれるようです。 public override void OnAgentRemoved(Agent affectedAgent, Agent affectorAgent, AgentState agentState, KillingBlow blow) { base.OnAgentRemoved(affectedAgent, affectorAgent, agentState, blow); _dataSource.OnAgentRemoved(affectedAgent); } // フォトモードで構図を決めている最中に GUI が表示されないようにするための処理です。 // この処理を入れても入れなくても、どちらにしろ出力される画像ファイルに GUI は写りません。 public override void OnPhotoModeActivated() { base.OnPhotoModeActivated(); _gauntletLayer._gauntletUIContext.ContextAlpha = 0f; } public override void OnPhotoModeDeactivated() { base.OnPhotoModeDeactivated(); _gauntletLayer._gauntletUIContext.ContextAlpha = 1f; } }} OpponentHealthVM.cs using System;using TaleWorlds.Library;using TaleWorlds.MountAndBlade; namespace OpponentHealthBar{ public class OpponentHealthVM ViewModel { private Agent _opponent; private int _currentValue; private int _maxValue; private string _strValues; private bool _isVisible; private const string ValueFormat = "{0} / {1}"; public OpponentHealthVM() { _opponent = null; _strValues = string.Empty; _isVisible = false; } [DataSourceProperty] public int CurrentValue { get = _currentValue; private set { if (_currentValue != value) { _currentValue = value; OnPropertyChangedWithValue(value, "CurrentValue"); } } } [DataSourceProperty] public int MaxValue { get = _maxValue; private set { if (_maxValue != value) { _maxValue = value; OnPropertyChangedWithValue(value, "MaxValue"); } } } [DataSourceProperty] public string StrValues { get = _strValues; private set { if (_strValues != value) { _strValues = value; OnPropertyChangedWithValue(value, "StrValues"); } } } [DataSourceProperty] public bool IsVisible { get = _isVisible; set { if (_isVisible != value) { _isVisible = value; OnPropertyChangedWithValue(value, "IsVisible"); } } } // GUI に表示するデータの更新はこのメソッドで行います。 // ただし、ここに記述すればあとは勝手に更新されていくというものではないので、 // 自分が必要な場所では自分で呼び出さなければなりません。 public override void RefreshValues() { base.RefreshValues(); // 元々ローカル変数だったものを、View から参照できるようにプロパティに昇格しました。 CurrentValue = (int)Math.Ceiling(_opponent?.Health ?? 0f); MaxValue = (int)Math.Ceiling(_opponent?.HealthLimit ?? 0f); StrValues = string.Format(ValueFormat, CurrentValue, MaxValue); IsVisible = _opponent != null; } public void OnFocusChanged(IFocusable focusableObject) { // 適切な相手に表示されるよう条件を追加しました。 if (focusableObject is Agent possibleOpponent possibleOpponent.IsHuman possibleOpponent.IsEnemyOf(Agent.Main)) { _opponent = (_opponent == null || _opponent != possibleOpponent) ? possibleOpponent null; RefreshValues(); } } public void OnAgentHit(Agent affectedAgent) { if (_opponent == affectedAgent) { RefreshValues(); } } public void OnAgentRemoved(Agent removedAgent) { if (_opponent == removedAgent) { // 先にフォーカスロストが発生してここには入らないかも。 OnFocusChanged(removedAgent); } } }} OpponentHealthBar.xml Prefab Window FillBarWidget WidthSizePolicy="Fixed" HeightSizePolicy="Fixed" SuggestedWidth="430" SuggestedHeight="50" HorizontalAlignment="Center" VerticalAlignment="Top" MarginTop="250" ContainerWidget="FillBarContainer" FillWidget="FillVisualParent\FillVisual" MaxAmount="@MaxValue" InitialAmount="@CurrentValue" IsVisible="@IsVisible" Children Widget Id="FillVisualParent" WidthSizePolicy="Fixed" HeightSizePolicy="StretchToParent" SuggestedWidth="400" HorizontalAlignment="Center" VerticalAlignment="Center" MarginTop="10" MarginBottom="10" Sprite="BlankWhiteSquare" Color="#202020A0" Children BrushWidget Id="FillVisual" WidthSizePolicy="Fixed" HeightSizePolicy="StretchToParent" SuggestedWidth="400" HorizontalAlignment="Left" Brush="Mission.MainAgentHUD.HeroHealthBar.Fill" / /Children /Widget Widget Id="FillBarContainer" WidthSizePolicy="StretchToParent" HeightSizePolicy="StretchToParent" Sprite="options_memory_progress_frame" / TextWidget Text="@StrValues" WidthSizePolicy="CoverChildren" HeightSizePolicy="CoverChildren" HorizontalAlignment="Center" VerticalAlignment="Center" PositionYOffset="3" Brush="Tooltip.Text" Brush.FontSize="24" / /Children /FillBarWidget /Window /Prefab 名前
https://w.atwiki.jp/battlefield1942/pages/579.html
大和MOD 作者:Akhenaten氏 作者様サイト:モッド図書館 :羅鬼くんち 最新バージョン:test MOD紹介(作者様HPより引用) 「男たちの大和」上演時に、いずれテレビで放送されることを見越して 映画の再現MODを作ろうとしたものの、ほったらかしになってるうちに 映画が放送されちゃったため、開発中の乗物やエフェクト、アニメーションの実験 用にちまちまいじっているMODです。ですので、マルチでプレイしても面白くないです。 大和 戦艦伊勢 列車砲 おまけ 大和、伊勢はcoopミッドウエーに登場、列車砲はrailgunというマップに登場します ダウンロード 作者様HPよりDL コメント サイトが落ちてるね DLできない -- 名無しさん (2021-05-23 17 48 13) 名前 コメント
https://w.atwiki.jp/akasatanahama/pages/65.html
概要 メタデータを使用し、一つのIDで複数のブロックを追加したり、向きを持つブロックを追加したりする。 ソースコード AluminiumMod.java package tutorial.aluminiummod; import net.minecraft.block.Block; import cpw.mods.fml.common.Mod; import cpw.mods.fml.common.Mod.EventHandler; import cpw.mods.fml.common.event.FMLPreInitializationEvent; import cpw.mods.fml.common.registry.GameRegistry; @Mod(modid = AluminiumMod.MODID, name = AluminiumMod.MODNAME, version = AluminiumMod.VERSION) public class AluminiumMod { public static final String MODID = "AluminiumMod"; public static final String MODNAME = "Aluminium Mod"; public static final String VERSION = "1.0.0"; public static Block blockAluminiumColored; @EventHandler public void perInit(FMLPreInitializationEvent event) { //ここは通常のブロックと同様。 blockAluminiumColored = new ColoredAluminiumBlock() .setBlockName("blockAluminiumColored") .setBlockTextureName("aluminiummod colored_aluminium_block"); GameRegistry.registerBlock(blockAluminiumColored, ItemColoredAluminiumBlock.class, "blockAluminiumColored"); } } ColoredAluminiumBlock.java package tutorial.aluminiummod; import java.util.List; import net.minecraft.block.Block; import net.minecraft.block.material.Material; import net.minecraft.client.renderer.texture.IIconRegister; import net.minecraft.creativetab.CreativeTabs; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.util.IIcon; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; public class ColoredAluminiumBlock extends Block { private IIcon[] iicon = new IIcon[16]; protected ColoredAluminiumBlock() { super(Material.rock); this.setCreativeTab(CreativeTabs.tabBlock); this.setHardness(5.0F); this.setResistance(10.0F); this.setStepSound(Block.soundTypeMetal); this.setHarvestLevel("pickaxe", 2); this.setLightLevel(0.0F); } @Override @SideOnly(Side.CLIENT) public void registerBlockIcons(IIconRegister register) { for (int i = 0; i 16; i ++) { this.iicon[i] = register.registerIcon(this.getTextureName() + "-" + i); } } @Override @SideOnly(Side.CLIENT) public IIcon getIcon(int side, int meta) { return iicon[meta]; } @Override @SideOnly(Side.CLIENT) public void getSubBlocks(Item item, CreativeTabs creativeTab, List list) { for (int i = 0; i 16; i ++) { list.add(new ItemStack(item, 1, i)); } } @Override public int damageDropped(int meta) { return meta; } } ItemColoredAluminiumBlock.java package tutorial.aluminiummod; import net.minecraft.block.Block; import net.minecraft.item.ItemBlockWithMetadata; import net.minecraft.item.ItemStack; public class ItemColoredAluminiumBlock extends ItemBlockWithMetadata { public ItemColoredAluminiumBlock(Block block) { super(block, block); } @Override public String getUnlocalizedName(ItemStack itemStack) { return this.getUnlocalizedName() + "." + itemStack.getItemDamage(); } } 解説 GameRegistry Block registerBlock(Block block, Class ? extends ItemBlock itemclass, String name) GameRegistryに追加ブロックを登録するメソッド。 対応するItemBlockを指定できる。 デフォルトではItemBlockを指定している。 Block void registerBlockIcons(IIconRegister register) ブロックのテクスチャを指定するメソッド。 Itemと同じ。 IIcon getIcon(int side, int meta) 描画時に呼ばれる。 第一引数では面を、第二引数ではメタデータを取得できる。 このメソッドを使えば面によって違うテクスチャを返したり、かまどのように向きを変えたりできる。 第一引数については下の「sideについて」で。 void getSubBlocks(Item item, CreativeTabs creativeTab, List list) クリエイティブタブに登録するメソッド。 Itemと同じ。 int damageDropped(int meta) ドロップアイテムのダメージを指定するメソッド。 Blockでは常に0を返しているのでオーバーライドする。 ItemBlockWithMetadata ItemBlockのサブクラスで、メタデータを使用するブロック用のクラス。 コンストラクタ(Block block, Block localBlock) 第一引数はスーパークラスのコンストラクタに渡し、第二引数はこのクラスで保持する。 String getUnlocalizedName(ItemStack itemStack) アイテムと同じ。 sideについて getIconの第一引数などのintは、面の方角を表している。 向きと座標の関係は、net.minecraft.util.FacingのoffsetsXForSide/offsetsYForSide/offsetsZForSideを使えばわかる side 向き 座標 0 下 y- 1 上 y+ 2 北 z- 3 南 z+ 4 西 x- 5 東 x+ 使用例 オファレンブロックを追加している部分。 +オファレンMOD OfalenModCore.java package nahama.ofalenmod; /*略*/ /**@author Akasata Nahama*/ @Mod(modid = OfalenModCore.MODID, name = OfalenModCore.MODNAME, version = OfalenModCore.VERSION) public class OfalenModCore { public static final String MODID = "OfalenMod"; public static final String MODNAME = "Ofalen Mod"; public static final String VERSION = "[1.7.10]1.0.0"; /*略*/ /**最初に行われる処理。アイテム・ブロックの追加などを行う*/ @EventHandler public void preInit(FMLPreInitializationEvent event) { /*略*/ //ブロックを設定するメソッドを実行 OfalenModBlockCore.registerBlock(); /*略*/ } /*略*/ } OfalenModBlockCore.java package nahama.ofalenmod.core; /*略*/ public class OfalenModBlockCore { *略*/ public static Block blockOfalen; /*略*/ /**ブロックを設定する*/ public static void registerBlock () { /*略*/ blockOfalen = new OfalenBlock() .setBlockName("blockOfalen") .setBlockTextureName("ofalenmod ofalen_block-"); GameRegistry.registerBlock(blockOfalen, ItemOfalenBlock.class, "blockOfalen"); /*略*/ } } OfalenBlock.java package nahama.ofalenmod.block; import java.util.List; import nahama.ofalenmod.OfalenModCore; import net.minecraft.block.Block; import net.minecraft.block.material.Material; import net.minecraft.client.renderer.texture.IIconRegister; import net.minecraft.creativetab.CreativeTabs; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.util.IIcon; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; public class OfalenBlock extends Block { private IIcon[] iicon = new IIcon[4]; public OfalenBlock() { super(Material.rock); this.setCreativeTab(OfalenModCore.tabOfalen); this.setHardness(7.5F); this.setResistance(15.0F); this.setStepSound(Block.soundTypeMetal); this.setLightLevel(1.0F); this.setHarvestLevel("pickaxe", 3); } /**メタデータ違いのテクスチャを登録する*/ @Override @SideOnly(Side.CLIENT) public void registerBlockIcons(IIconRegister register) { for (int i = 0; i 4; i ++) { this.iicon[i] = register.registerIcon(this.getTextureName() + i); } } /**メタデータにより返すIIconを変える*/ @Override @SideOnly(Side.CLIENT) public IIcon getIcon(int side, int meta) { return iicon[meta 3]; } /**メタデータ違いのブロックを登録する*/ @Override @SideOnly(Side.CLIENT) public void getSubBlocks(Item item, CreativeTabs creativeTab, List list) { for (int i = 0; i 4; i ++) { list.add(new ItemStack(item, 1, i)); } } /**メタデータによりドロップ品を変える*/ @Override public int damageDropped(int meta) { return meta 3; } } ItemOfalenBlock.java package nahama.ofalenmod.itemblock; import net.minecraft.block.Block; import net.minecraft.item.ItemBlockWithMetadata; import net.minecraft.item.ItemStack; public class ItemOfalenBlock extends ItemBlockWithMetadata { public ItemOfalenBlock(Block block) { super(block, block); } /**メタデータにより内部名を変える*/ @Override public String getUnlocalizedName(ItemStack itemStack) { return this.getUnlocalizedName() + "." + itemStack.getItemDamage(); } } コメント この項目に関する質問などをどうぞ。 かまどみたいに置く向きによって変わるのってどうして作るんですか? - 名無しさん 2015-10-12 21 07 02 onBlockPlacedByをオーバーライドし、置いたプレイヤーの向きによって、メタデータを設定します。バニラのBlockFurnaceや、オファレンMODのBlockSmeltingMachineなどが参考になるかと思います。 - 赤砂蛇凪浜 2015-10-13 08 36 08 メタデータによって上面のテクスチャだけを変えるにはどうすればいいですか? - 名無しさん 2016-06-10 23 03 47 IIconをあらかじめ用意しておき、getIconでsideとmetadataの判定をして返すIIconをかえればよいです。 - 赤砂蛇凪浜 2016-06-11 06 52 52 Optifineのように隣り合ったガラスの縁を消すのにはメタデータの違うブロックを置き換えればよいですか? - 名無しさん 2016-06-12 00 31 06 BFOのフチなしガラスでは、getIcon(IBlockAccess,int,int,int,int)で判定を行い、IIconを返しています。メタデータを使う必要はありません。 - 赤砂蛇凪浜 2016-06-12 06 59 29 通常のブロック追加では一つ画像のみでいくらブロックをおいても同じ柄ですが、8×8の64枚の画像をrepeatの形で適応させるにはどう作れば良いのですか?? - 名無しさん 2016-06-14 17 45 47 返答遅くなりまして申し訳ありません。アニメーションさせたい場合は、まず、アニメーションさせたいブロックのテクスチャを、アニメーション順に縦に並べてください。次に、ブロックのテクスチャと同じ階層に[ブロック名].png.mcmeta というファイルを作って、以下のように記述してください。 { "animation" { "frametime" 2 } } アニメーションの速度が速ければ、"frametime"の数値を上げてください。バニラのリソースでは、火や溶岩が参考になるかと思います。- Tom Kate 2016-06-25 11 36 47 メタ付の半ブロックを追加するにはどうすればいいのでしょうか? - 名無しさん 2017-04-20 19 50 42 返信が遅くなってしまい申し訳ありません。コメントを別のページから移動させて頂きました。ご了承ください。単純なものであれば、BlockStoneSlabやBlockWoodSlabをコピペし、各メソッド内でインスタンスの呼び出しをしている部分を置き換えればよいです。ただし、BlockSlabの一部メソッドやItemなど他のクラスでもインスタンスを呼び出しているので、それらも考慮する必要があると思われます。今後、ハーフブロックの追加に関するチュートリアルを作成する予定です。 こちらはマイクラバージョン1.10や1.11などでも使えるのでしょうか...? - 名無しさん 2017-06-08 23 17 07 ver1.8以降はBlockStateと言うものを利用いたしますのでこのチュートリアルは使用できません。 - Tom Kate 2017-06-09 19 13 51 かまどではなく、原木や柱状クオーツのように横から置くとtopの部分が横を向くようにするには、どうすればよいでしょうか? - 名無しさん 2017-06-21 21 22 17 返信が遅くなってしまい申し訳ありません。単純なものでしたら、BlockRotatedPillarを継承し、BlockHayを参考にgetSideIconとregisterBlockIconsをオーバーライドすればできます。継承関係があり少々複雑ですが、原木のクラス(BlockLog, BlockOldLog, BlockNewLog)を見れば一つのIDで四種類まで追加できるかと思います。BlockRotatedPillarでは、getRenderTypeで柱状のレンダーを指定し、横向き設置時にテクスチャを回転させています。また、onBlockPlacedで設置する支えとなったブロックの面によりメタデータで向きを設定し、getIconでメタデータにより断面のテクスチャの向きを変更しています。 - 赤砂蛇凪浜 2017-07-08 18 06 57 名前
https://w.atwiki.jp/suzuremonserver/pages/23.html
日本語Mod導入方法 本サーバーは日本語Mod推奨となっています。 導入については下記からどうぞ。 必要なもの ・7ZIP→sevenzip.sourceforge.jp/ ・日本語化Mod→forum.minecraftuser.jp/viewtopic.php 導入手順 1、上記のURLから日本語化MODをダウンロードし解凍する。 解凍した中身↓ 2、デスクトップのスタートを押し、C \Users\ユーザ名\AppData\Roaming\.minecraft と進める。AppDateが見当たらない場合は、ページ最後部参照。 .minecraftを開くと下記の画像のように表示される(画像は一部) 3、フォルダのbinを開き「minecraft.jar」もしくわ「minecraft」を 右クリックし「7ZIP」で開く。開いたときの画像↓ 3、開いたらまず、「META-INF」を右クリック、削除。 そして「1」で解凍した、日本語のフォルダ「bin」を開き 「client」の中身を全部ドラッグ&ドロップで、7Zipで開いてる中に入れる。 左が7ZIP・右がダウンロードした日本語MODの中身 追加すると同時に[はい・いいえ・キャンセル]と聞かれるので「はい」を選択。 4、これで難しい事は終わり。 最後に、「1」でダウンロードしたファイルの中に「font」というフォルダがあるので それを、「.minecraftの中のresourcesフォルダ」にフォルダー事追加。 画像は、resourcesの中にfontフォルダを入れた後の画像 5、これで日本語化は出来ています。あとはゲームが正常に起動するかが問題です。 起動しなかった場合は、「2」の画像にある「bin」を削除しゲームを起動して 導入を最初からやり直してください。
https://w.atwiki.jp/wot_tif/pages/22.html
MODは好きな様に入れてもいいのですが、公式が禁止しているMODがあります なお、ここに書いてあるMODを入れてる場合。BANされる可能性があります 1.レーザーサイトMOD 砲口から伸びる赤い線を表示し、どこを照準しているか一目瞭然になるため 2.フリーカメラMOD ※フリーカメラ≠ズームアウトMOD 自走砲でスナイパーモードにできたり、視点を自由に移動できるなど、ゲーム性が破綻するため こんなのやこんなの(YouTubeへリンクします) クソゲーである 3.モジュール当たり判定を3Dモデルで可視化するMOD 乗務員や弾薬庫などの当たり判定を表示させるため ・例 4.木の葉や茂みを消すMOD このムロバンカを見てくれ、こいつはどう思う すごく・・スッキリしてます・・ マジカルフォレストなんてなかった!! 5.ズームアウトMOD 自走砲視点でカメラを引ける範囲を拡張するMOD。(通常視点はセーフ) カウンターがやりやすくなるね、やったねt 6.トレーサーMOD 自走砲視点で、見えない敵の履帯跡を表示させるMODのこと
https://w.atwiki.jp/mootchiiy/pages/65.html
このページでは、Super Smash Flash 2(SSF2) Sandboxで動作するModを列挙する。これらのModは、ダウンロードリンクが公開されており、なおかつ実際に動作した物のみ。各作者のDiscordなどに入ることでより多くのModをダウンロードできることもあるが、それは各自で調べてほしい。 Modの簡単導入 まず、Sandboxをダウンロードすること。 次に、Sandboxを展開したフォルダのbuild/data/character/に、次の表を見てダウンロードしたssfファイルを入れる。多くの場合、ファイル名は『DAT52.ssf』などとなっているが、キャラクターの判別のために分かりやすいファイル名へ変更しておくこと。 最後にbuild/res/Mappings.jsonを開き、myCharactersという項目に先ほどのファイル名(拡張子ssfは除く)を並べる。入力の仕方はデフォルトで例が入っているため、それを参考にしてほしい。なお一列に並べられるのは13キャラクターのみなので、いっぱいになったら下の行へ移動すること。 Mod一覧 作品名、キャラ名のあいうえお順で並べている。 作品名 キャラ名 ダウンロードリンク 注意点 メモ Among Us クルーメイト(Crewmate) https //www.mediafire.com/file/b69zr3i1yegpoiv/SSF2_0.9b_Mods_-_Crewmate.zip/file 実のところインポスター。 Angry Birds Red Bird https //www.mediafire.com/file/al5r7ztv6wnczj6/RED+FIXED.rar/file ボンバーマンのグラフィック置き換え。 Deltarune ジェビル(Jevil) https //drive.google.com/drive/folders/19CELEbW8WJDn954mA-Ls5AMWtT42ae5J Deltarune ラルセイ(Ralsei) https //drive.google.com/drive/folders/19CELEbW8WJDn954mA-Ls5AMWtT42ae5J 必殺技をはじめとする各種技がない。 Deltarune スパムトン(Spamton) https //drive.google.com/drive/folders/19CELEbW8WJDn954mA-Ls5AMWtT42ae5J Friday Night Funkin' Boyfriend+Girlfriend https //www.mediafire.com/file/vvk1jnspckozhk3/SSF2_Mod_Boyfriend.rar/file NARUTO うちはイタチ https //drive.google.com/drive/folders/19CELEbW8WJDn954mA-Ls5AMWtT42ae5J 復帰がかなり強い。 NARUTO はたけカカシ https //drive.google.com/drive/folders/19CELEbW8WJDn954mA-Ls5AMWtT42ae5J Undertale ウザいイヌ(Annoying Dog) https //drive.google.com/drive/folders/19CELEbW8WJDn954mA-Ls5AMWtT42ae5J Undertale サンズ(Sans) https //videogamemods.com/supersmashflash2/mods/sans-but-its-a-joke-mod/ ぶっ壊れ。上下左右の攻撃で重力操作が撃てるが、ステージ上すべての敵に攻撃する。CPであれば、0%の時点から10秒弱で上に吹き飛ばすことすら可能。 VOCALOID 初音ミク https //www.mediafire.com/file/n75so24jwqa8aq6/DAT15%2528mod_de_hatsune_miku%2529.rar/file ゼルダのグラフィック置き換え。 犬夜叉 犬夜叉 https //videogamemods.com/supersmashflash2/mods/inuyasha-revamped/ イチゴのグラフィック置き換え。 エル・チャボ・デル・オチョ El Chavo https //gamebanana.com/mods/452845 鬼滅の刃 竈門炭次郎 https //sites.google.com/view/chimueladasepicasalaborger/mods ロイドのグラフィック置き換え。 銀魂 坂田銀時 https //www.mediafire.com/file/4bb4a9qdktxk56m/SSF2_Sakata_Gintoki.zip/file ぶっ壊れ気味。 パーセントが一定数(おそらく80%)を越えると技が一式切り替わる。正直普通の時の方が強い。 進撃の巨人 エレン・イェーガー https //www.mediafire.com/file/67zs2fgwet7e70l/Eren_Jaeger.rar/file フォックスのグラフィック置き換え。 呪術廻戦 伏黒恵 https //www.mediafire.com/file/d111rsmeqr3f80c/Megumi_Fushiguro.zip/file 必殺技がない。また、大幅にラグくなる。 呪術廻戦 釘崎野薔薇 https //www.mediafire.com/file/54z4g477x6iucw2/Nobara.rar/file 大幅にラグくなる。 呪術廻戦 虎杖雄仁 https //www.mediafire.com/file/n66um7bk61fxsnr/Yuji_Itadori.zip/file かなりぶっ壊れ。大幅にラグくなる。 ジョジョの奇妙な冒険 東方仗助(クレイジーダイヤモンド)+浩一(エコーズACT2)+億康(ザ・ハンド)+露伴(ヘブンズドアー)+承太郎(スタープラチナ・ザ・ワールド) https //drive.google.com/drive/folders/19CELEbW8WJDn954mA-Ls5AMWtT42ae5J ザ・ハンドが非常に強力なため下からの復帰ならかなりやりやすい。瞬間移動という仕様上、終点の真下からザ・ハンドを使うと床を貫通して上に戻ってくることができる。 ジョジョの奇妙な冒険 吉良吉影(キラークイーン) https //drive.google.com/drive/folders/19CELEbW8WJDn954mA-Ls5AMWtT42ae5J ジョジョの奇妙な冒険 花京院典明(ハイエロファントグリーン) https //www.mediafire.com/file/z5c1tdu9d13a3qo/Kakyoin_SSF2.zip/file 復帰技が独特でかなり上級者向け。 ゼルダの伝説 こどもリンク https //gamebanana.com/mods/385449 下必殺の爆弾設置をすると爆弾が消えないため、非常にラグくなる。 ソードアートオンライン キリト https //www.mediafire.com/file/204e5ai6u3vxb40/Kirito+SSF2.rar/file ほぼソラのグラフィック置き換え。 ソニック・ザ・ヘッジホッグ サニック(Sanic) https //drive.google.com/drive/folders/19CELEbW8WJDn954mA-Ls5AMWtT42ae5J グラフィックがないため、技がちゃんと使えているかとても分かりづらい。 チェンソーマン デンジ+マキマ+パワー+アキ+サメの魔人 https //www.mediafire.com/file/sv33blqq7ahyhod/Denji_%257B_DAT66_%257D.ssf/file 上必殺でかなりの距離を飛べるため、復帰がすごく強い。終点くぐりもできなくもなさそう。 月姫 ネコアルク https //drive.google.com/drive/folders/19CELEbW8WJDn954mA-Ls5AMWtT42ae5J フォックスのグラフィック置き換え。 鋼の錬金術師 エドワード・エルリック+アルフォンス・エルリック+ロイ・マスタング https //videogamemods.com/supersmashflash2/mods/edward-elric/ 鋼の錬金術師 ロイ・マスタング https //sites.google.com/view/chimueladasepicasalaborger/mods キャプテンファルコンのグラフィック置き換え。 ハンターハンター キルア https //www.mediafire.com/file/63a49l8jc1d84dh/Killua+HxH+stage_SSF2.zip 復帰技が独特。また空中で通常必殺を撃ち続けるとホバリングができる。 光神話・パルテナの鏡 パルテナ https //gamebanana.com/mods/366731 ファイヤーエムブレム Roy https //gamebanana.com/mods/365698 Marthのグラフィック違い? ダウンロードリンクにはMeleeとUltimateの二種類が用意されているが、著者は違いがよく分からない。 ペルソナ ジョーカー https //videogamemods.com/supersmashflash2/mods/joker-v2/ スマッシュブラザーズとは違い、ダメージを受けても強化されない。下必殺が反撃になっている。 僕のヒーローアカデミア 爆轟勝己 https //sites.google.com/view/chimueladasepicasalaborger/mods ゼルダのグラフィック置き換え。 ポケットモンスター エースバーン(Cinderace) https //gamebanana.com/mods/453349 メタルギアソリッド 雷電 https //sites.google.com/view/chimueladasepicasalaborger/mods ほぼロイドのグラフィック置き換え。 妖怪ウォッチ ジバニャン+ウィスパー https //www.mediafire.com/file/cito9onq9i0zqb5/Jibanyan+(FIXED).rar/file ほぼソラのグラフィック置き換え。 ワンパンマン サイタマ https //drive.google.com/drive/folders/19CELEbW8WJDn954mA-Ls5AMWtT42ae5J ぶっ壊れ。頭突きが非常に強く、0%でも即死可能。無限ジャンプもできる。
https://w.atwiki.jp/civilization/pages/279.html
MOD/Tan Interface スクリーンショット1 2 3 4 Site Download インターフェイスの色をCiv3風の落ち着いた褐色に変えます。 詳しくはスクリーンショットを参照してください。 インストール方法 Civ4のディレクトリ/Resource/Themes/Civ4/Civ4Theme_Common.thmをリネームする MODをダウンロード 上記ディレクトリにコピーCiv4Theme_Common.thmをコピー
https://w.atwiki.jp/ps_s/pages/162.html
考案者 名前 ballsgin mod 価格:約850円 ballsgin modでも色々あるが、ここでは、bonkuraさんが使用していたものを紹介しています。 【作り方】 -材料- Ballsign ×2 Dr.Grip ×1 SuperGrip ×2 1.二本あるうちの一本のBallsignのキャップを取り、ペン先をペンチやら何やらで引っ張って中のインクチューブを取り出す。 2.1で作ったものの両端にBallsignのキャップを取り付け、SuperGripのグリップをメモリのある部分で切ったものを はめる。 3.2でSuperGeipをつけたもののうえに、Dr.Gripのグリップを適当な大きさに切ったものをはめて、完成。 ※少し軽いなと思う方は両端にuni ball Signoのチップをはめるとよいです。
https://w.atwiki.jp/3dcustom/pages/52.html
前準備 【必要なソフトウェア】 一部のソフトを動かすために.NET Framework 3.5が必要です(既に導入されている場合はいらないです) Microsoft .NET Framework 3.5 ダウンロードしてサクっとインストールしておいてください。念のため再起動もするとGoodです もしインストール方法が分からない方がいればググってみてください。グーグル先生は偉大です windows2000環境では .NET Framework 2.0 までしかインストールできません しかし、以下の各ツールの基本機能はある程度利用可能です 自己責任で不具合解析ができる人であれば追加mod作成は可能です さあMOD制作に必要なソフトウェアを全部まとめて入手してしまいましょう TAHdecGUI tahファイルを解凍・梱包するソフトです Tso2Mqo tahファイルの中に入っているtsoファイルを メタセコイアで編集できる形に変換するコンバーターです cgfxShader簡易編集ツール cgfxShaderファイルを簡単に編集するための専用エディターです この3つのソフトはTech Arts UP LOADER CUSTOMから入手してください 参考 TAH・TSOファイルの展開方法 Metasequoia http //www.metaseq.net/ 3Dモデリングソフト(シェアウェア)です シェアウェア版とフリーソフト版がありますが どちらも無料で使用可能です(機能は制限されます) フリーソフト版は機能が非常に限定されるためMOD作成には適していません シェアウェア(有料)版がお奨めです。前述の通り無料で使えます GIMP http //www.gimp.org/ フリーの画像編集ソフトです。これで「テクスチャ」と呼ばれる、3Dモデルに貼り付ける画像を編集します Photoshopがある人はそちらを使った方が無難ですが いかんせんフォトショは高いので持ってない人はGIMPをインストールしてください 英語がダメ、ダウンロードやインストール方法が分からないという人はググってみてください Google先生はGreatです 以下2つは無くてもMOD作成は可能です。ですが自分のやり方ではあると便利です Stirling http //www.vector.co.jp/soft/win95/util/se079072.html バイナリ編集ソフトです。後にこのソフトを使ってファイルの一部を改変することになります 既に愛用のエディタがある人はそちらを使ってください このソフトは既に藻消の際にインストールしてある人が多いのではないでしょうか? 後々問題を起こすかもしれないので、環境設定からバックアップファイルを作らない様に設定してください 自分でバックアップを取る癖を付けるのも良いことです 練馬 http //www.vector.co.jp/soft/win95/util/se256851.html ネリーm・・・リネーマーです。ファイルの名前を自由自在に変更できます 普段使う分にも便利ですね。既に愛用のリネーマーがある人はそちらを使ってください 以上のソフトウェアが有ればMODを制作することができます インストール先ですがCドライブ直下にTEMPフォルダを作り、そこにTAHdecGUIとTso2MqoGuiをインストールし GIMPやメタセコイアなどのショートカットを置いたりすることをおすすめします これ以降の作業は下手するとタスクバーを見て絶句する位煩雑な作業になります(ワイドモニタマジオヌヌメ) できるだけ、アクセスしやすく便利にしておいた方が良いです それと、今回は恐らく大丈夫ですが一部のMOD制作ソフトはフルパスにスペース(半角含む)や2バイト文字が含まれていると 正常に動作しなくなってしまいます。念のため、こうしておきましょう 次はメタセコイアを使って3Dモデルを作ります Go!→メタセコイアで3Dモデルを作る
https://w.atwiki.jp/rtourer/pages/23.html
ここに書いてる情報は開発段階のものなので いつか一部変更または追加される可能性が高いです。 MOD仕様 ./data/model/car/***/フォルダの中に /車名/フォルダを作り、その中に /data/、/model/、/se/ フォルダを置く /***/というのは車を分けるフォルダで、下の図でいう[Default]フォルダのこと ↑こんな風に /data/ data.cdf ・・・車のスペック設定ファイル engine.cdf ・・・車のエンジン設定ファイル sound.cdf ・・・車のサウンド設定ファイル dispinfo.ini・・・HUDやらの設定ファイル dispinfo.ini以外はそれぞれエディターを使って作成できます。 使い方はそれぞれのReadMeに書いてます。 dispinfo.iniについて /model/ car.sig ・・・車の3Dモデル in.sig ・・・車の内装3Dモデル handle.sig ・・・車のハンドル3Dモデル 外観モデル 3D空間の1が0.1mになるようにし、RokDeBone2を使ってsig形式で出力してください。 Y座標は車の底が0になるようにして、車データ設定のときに重心高をきめてください。 車を横から見て、前輪と後輪のちょうど間に軸(原点)が来るようにしてください。 (ゲーム内でのタイヤの前後左右位置は車データのホイールベース、全幅から自動で決定されます) ブレーキ時に点灯させたい部分のパーツ名を blight にしてください。 名前が「mat1」のマテリアルには環境マッピングっぽいものが適用されます。 ドライバーを座らせる位置に isu ボーンをつくります。 内装モデル 仕様は外観モデルと同じです。 ドライバーを座らせる位置に isu ボーンをつくります。 コックピット視点では、こちらのisuボーンから視点を決定します。 ハンドルの位置に handle ボーンをつくります。 タコメータを表示させたいところに板ポリゴンを設置し、マテリアル(材質)「takom」で塗ります。 バックミラーを表示させたいところに板ポリゴンを設置し、「backmir」で塗ります。 (上下逆さだったりしたらポリゴンを判定させてください。) 色々と面倒なのでデフォルト使いまわしでもなんとかなります。 /se/ 車のサウンド設定ファイルで指定したファイルを置く。 1chモノラルにする。